package com.yingsheng.bi.hks.template.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.databind.util.StdDateFormat;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class Jackson {

    static final TypeReference<Map<String, Object>> mapTypeReference = new TypeReference<Map<String, Object>>() {
    };
    static final TypeReference<List<Object>> listTypeReference = new TypeReference<List<Object>>() {
    };
    private DateFormat dateFormat;
    private ObjectMapper objectMapper;
    private boolean pascalCamel;
    private boolean underscores;
    private boolean numString;
    private boolean bigDecimalString;
    private boolean longString;
    private boolean failUnknown;

    public Jackson() {
        this.dateFormat = new Jackson.MyDateFormat();
        this.pascalCamel = false;
        this.underscores = false;
        this.numString = false;
        this.bigDecimalString = false;
        this.longString = true;
        this.init();
    }

    public void init() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        objectMapper.setDateFormat(this.dateFormat);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, this.failUnknown);
        if (this.pascalCamel) {
            objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
        }
        if (this.underscores) {
            objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        }
        if (this.numString) {
            objectMapper.configure(com.fasterxml.jackson.core.JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, true);
        } else {
            if (this.bigDecimalString) {
                objectMapper.configure(com.fasterxml.jackson.core.JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, this.bigDecimalString);
            }
            if (this.longString) {
                SimpleModule module = new SimpleModule("LongModule");
                module.addSerializer(Long.TYPE, ToStringSerializer.instance);
                module.addSerializer(Long.class, ToStringSerializer.instance);
                objectMapper.registerModule(module);
            }
        }
        this.setObjectMapper(objectMapper);
    }

    public void setObjectMapper(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    public void setDateFormat(DateFormat dateFormat) {
        this.dateFormat = dateFormat;
    }

    public void setPascalCamel(boolean camel) {
        this.pascalCamel = camel;
    }

    public void setUnderscores(boolean underscores) {
        this.underscores = underscores;
    }

    public void setNumString(boolean numString) {
        this.numString = numString;
    }

    public void setBigDecimalString(boolean bigDecimalString) {
        this.bigDecimalString = bigDecimalString;
    }

    public void setLongString(boolean longString) {
        this.longString = longString;
    }

    public void setFailUnknown(boolean failUnknown) {
        this.failUnknown = failUnknown;
    }

    public String obj2json(Object obj) throws IOException {
        return this.objectMapper.writeValueAsString(obj);
    }

    public <T> T json2pojo(String jsonStr, Class<T> clazz) throws IOException {
        return this.objectMapper.readValue(jsonStr, clazz);
    }

    public Map<String, Object> json2map(String jsonStr) throws IOException {
        return this.objectMapper.readValue(jsonStr, mapTypeReference);
    }

    public <T> Map<String, T> json2map(String jsonStr, Class<T> clazz) throws IOException {
        Map<String, Map<String, Object>> map = (Map) this.objectMapper.readValue(jsonStr, mapTypeReference);
        Map<String, T> result = new HashMap();
        Iterator var6 = map.entrySet().iterator();

        while (var6.hasNext()) {
            Map.Entry<String, Map<String, Object>> entry = (Map.Entry) var6.next();
            Object value = entry.getValue();
            result.put(entry.getKey(), value == null ? null : this.map2pojo(entry.getValue(), clazz));
        }

        return result;
    }

    public <T> List<T> json2list(String jsonArrayStr, Class<T> clazz) throws IOException {
        List<Map<String, Object>> list = (List) this.objectMapper.readValue(jsonArrayStr, listTypeReference);
        List<T> result = new ArrayList();
        Iterator var6 = list.iterator();

        while (var6.hasNext()) {
            Map<String, Object> map = (Map) var6.next();
            result.add(map == null ? null : this.map2pojo(map, clazz));
        }

        return result;
    }

    public <T> T obj2obj(Object srcObj, Class<T> distClazz) throws IOException {
        return srcObj instanceof Map ? this.map2pojo(srcObj, distClazz) : this.map2pojo(this.pojo2map(srcObj), distClazz);
    }

    public <T> T map2pojo(Object map, Class<T> clazz) {
        return this.objectMapper.convertValue(map, clazz);
    }

    public Map<String, Object> pojo2map(Object obj) {
        return this.objectMapper.convertValue(obj, mapTypeReference);
    }

    static class MyDateFormat extends StdDateFormat {
        private static final long serialVersionUID = -3589462866719016815L;
        protected static final String TIME_FORMAT_STR = "yyyy-MM-dd HH:mm:ss.SSS";
        protected static final String DATE_FORMAT_STR = "yyyy-MM-dd HH:mm:ss";

        public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
            return date instanceof Timestamp ? (new SimpleDateFormat(TIME_FORMAT_STR)).format(date, toAppendTo, fieldPosition) : (new SimpleDateFormat(DATE_FORMAT_STR)).format(date, toAppendTo, fieldPosition);
        }

        public Date parse(String dateStr) throws ParseException {
            dateStr = dateStr.trim();
            if (dateStr.length() == TIME_FORMAT_STR.length()) {
                return (new SimpleDateFormat(TIME_FORMAT_STR)).parse(dateStr);
            } else {
                return dateStr.length() == DATE_FORMAT_STR.length() ? (new SimpleDateFormat(DATE_FORMAT_STR)).parse(dateStr) : super.parse(dateStr);
            }
        }

        public MyDateFormat clone() {
            return new MyDateFormat();
        }
    }

}
